<template>
  <div class="box-wrap">
    <div ref="container" class="term-wrap"></div>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount, watch, onActivated } from 'vue'
import { useRoute } from 'vue-router'
import '@xterm/xterm/css/xterm.css'
import { Terminal } from '@xterm/xterm'
import { FitAddon } from '@xterm/addon-fit'
import { useTabStore } from '@/stores/tabStore'
import { storeToRefs } from 'pinia'
import { CanvasAddon } from '@xterm/addon-canvas'
import { ImageAddon } from '@xterm/addon-image'

const route = useRoute()
const id = route.query.id
const fitAddon = ref({})
const term = ref({})
const container = ref({})
const websockt = ref(null)
const { closeId } = storeToRefs(useTabStore())

const customSettings = {
  enableSizeReports: true, // whether to enable CSI t reports (see below)
  pixelLimit: 16777216, // max. pixel size of a single image
  sixelSupport: true, // enable sixel support
  sixelScrolling: true, // whether to scroll on image output
  sixelPaletteLimit: 256, // initial sixel palette size
  sixelSizeLimit: 25000000, // size limit of a single sixel sequence
  storageLimit: 128, // FIFO storage limit in MB
  showPlaceholder: true, // whether to show a placeholder for evicted images
  iipSupport: true, // enable iTerm IIP support
  iipSizeLimit: 20000000 // size limit of a single IIP sequence
}

const connData = {
  id: id,
  type: 'local-conn'
}

onMounted(() => {
  handleConn()
  window.addEventListener('resize', () => {
    fitAddon.value.fit()
    if (websockt.value.readyState == 1) {
      const resizeData = {
        id: id,
        type: 'local-resize',
        cols: term.value.cols,
        rows: term.value.rows
      }
      websocketsend(JSON.stringify(resizeData))
    }
  })
})

const handleConn = () => {
  if (websockt.value) {
    return
  }
  term.value = buildTerminal()
  fitAddon.value = new FitAddon()
  term.value.loadAddon(fitAddon.value)
  term.value.loadAddon(new CanvasAddon())
  term.value.loadAddon(new ImageAddon(customSettings))
  term.value.open(container.value)
  fitAddon.value.fit()
  connData.cols = term.value.cols
  connData.rows = term.value.rows

  websockt.value = new WebSocket('ws://localhost:10095')
  websockt.value.onmessage = websocketonmessage
  websockt.value.onopen = websocketonopen
  websockt.value.onerror = websocketonerror
  websockt.value.onclose = websocketclose

  term.value.onData((data) => {
    //键盘输入时的回调函数
    const cmdData = {
      id: id,
      type: 'local-cmd',
      cmd: data
    }
    websocketsend(JSON.stringify(cmdData))
  })
}

const websocketonopen = () => {
  websocketsend(JSON.stringify(connData))
}

const websocketonerror = (error) => {
  console.log('websocketonerror:', error)
}

const websocketonmessage = (e) => {
  const msg = JSON.parse(e.data)
  term.value.write(msg.data)
}

const websocketsend = (data) => {
  websockt.value.send(data)
}

const websocketclose = (e) => {
  console.log('断开连接', e)
}

onBeforeUnmount(() => {
  websockt.value.close()
})

window.onbeforeunload = function () {
  websockt.value.close()
}

const buildTerminal = () => {
  const term = new Terminal({
    cursorBlink: true, // 光标闪烁
    cursorStyle: 'block', // 光标样式  null | 'block' | 'underline' | 'bar'
    scrollback: 1000, //回滚
    tabStopWidth: 4, //制表宽度
    convertEol: true,
    encoding: 'utf8'
  })
  return term
}

watch(closeId, (New, Old) => {
  console.log(`新值:${New} ——— 老值:${Old}`)
  if (New === id) {
    websockt.value.close()
  }
})

onActivated(() => {
  fitAddon.value.fit()
  if (websockt.value.readyState == 1) {
    const resizeData = {
      id: id,
      type: 'local-resize',
      cols: term.value.cols,
      rows: term.value.rows
    }
    websocketsend(JSON.stringify(resizeData))
  }
})
</script>

<style lang="less" scoped>
.box-wrap {
  width: 100vw;
  background-color: black;
  .term-wrap {
    height: calc(100vh - 71px);
    padding-left: 1px;
  }
}
</style>
